
package com.chongchong.auth.controller;

import com.chongchong.auth.granter.CaptchaTokenGranter;
import com.chongchong.auth.granter.ITokenGranter;
import com.chongchong.auth.granter.TokenGranterBuilder;
import com.chongchong.auth.granter.TokenParameter;
import com.chongchong.auth.utils.TokenUtil;
import com.chongchong.common.cache.CacheNames;
import com.chongchong.common.constant.StaticConstant;
import com.chongchong.common.tool.EmailCommonUtil;
import com.chongchong.core.secure.AuthInfo;
import com.chongchong.core.tool.api.R;
import com.chongchong.core.tool.support.Kv;
import com.chongchong.core.tool.utils.*;
import com.chongchong.user.entity.User;
import com.chongchong.user.entity.UserInfo;
import com.chongchong.user.feign.IUserClient;
import com.google.code.kaptcha.Producer;
import com.wf.captcha.SpecCaptcha;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;

/**
 * 认证模块
 *
 * @author
 */
@RestController
//@AllArgsConstructor
@Api(value = "用户授权认证", tags = "授权接口")
public class AuthController {

	@Autowired
	private RedisUtil redisUtil;

	@Resource(name = "captchaProducer")
	private Producer captchaProducer;

	@Resource(name = "captchaProducerMath")
	private Producer captchaProducerMath;
	@Autowired
	private IUserClient userClient;
	@Autowired
	private EmailCommonUtil emailCommonUtil;
	@Autowired
	private CaptchaTokenGranter captchaTokenGranter;
	@Value("${password.validTime}")
	private Long passwordValidTime;
	@PostMapping("token")
	@ApiOperation(value = "获取认证token", notes = "传入租户ID:tenantId,账号:account,密码:password")
	public R<AuthInfo> token(@ApiParam(value = "授权类型", required = true) @RequestParam(defaultValue = "password", required = false) String grantType,
							 @ApiParam(value = "刷新令牌") @RequestParam(required = false) String refreshToken,
							 @ApiParam(value = "租户ID", required = true) @RequestParam(defaultValue = "000000", required = false) String tenantId,
							 @ApiParam(value = "账号") @RequestParam(required = false) String account,
							 @ApiParam(value = "密码") @RequestParam(required = false) String password) {

		String userType = Func.toStr(WebUtil.getRequest().getHeader(TokenUtil.USER_TYPE_HEADER_KEY), TokenUtil.DEFAULT_USER_TYPE);

		TokenParameter tokenParameter = new TokenParameter();
		tokenParameter.getArgs().set("tenantId", tenantId)
			.set("account", account)
			.set("password", password)
			.set("grantType", grantType)
			.set("refreshToken", refreshToken)
			.set("userType", userType);

		ITokenGranter granter = TokenGranterBuilder.getGranter(grantType);
		UserInfo userInfo = granter.grant(tokenParameter);

		if (userInfo == null || userInfo.getUser() == null || userInfo.getUser().getId() == null) {
			return R.fail(TokenUtil.USER_NOT_FOUND);
		}
		//判断密码是否过期
		Long id = userInfo.getUser().getId();
		R<UserInfo> userInfoR = userClient.userInfo(id);
		if (userInfoR != null) {
			UserInfo data = userInfoR.getData();
			if(data != null && data.getUser() != null){
				long betweenDays;
				Date date = new Date();
				User user = data.getUser();
				Date passwordUpdate = user.getPasswordUpdate();
				if(passwordUpdate == null){
					return R.fail(455,TokenUtil.USER_PASSWORD_AGING);
				}else {
					betweenDays = DateUtil.betweenDays(passwordUpdate, date);
				}
				if(passwordValidTime < betweenDays){
					return R.fail(455,TokenUtil.USER_PASSWORD_AGING);
				}
			}
		}

		return R.data(TokenUtil.createAuthInfo(userInfo));
	}

	/**
	 * 忘记密码接口
	 *
	 * @param
	 * @return R<?>
	 * @author wuning
	 * @date 2022/9/8 9:54
	 */
	@PostMapping("/forgetThePassword")
	@ApiOperation(value = "忘记密码接口")
	public R<?> forgetThePassword(@ApiParam(value = "账号", required = true) @RequestParam String account,
								  @ApiParam(value = "邮箱", required = true) @RequestParam String email,
								  @ApiParam(value = "租户ID", required = true) @RequestParam(defaultValue = "000000", required = false) String tenantId) {
		//临时取消验证码
//		captchaTokenGranter.verifyCode();
		String emailMatcher = "^[A-Za-z0-9\u4e00-\u9fa5]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+$";
		boolean isMatch = Pattern.matches(emailMatcher, email);
		if (!isMatch) {
			return R.fail(500, TokenUtil.USER_EMAIL_FORMAT);
		}
		if (StringUtils.isEmpty(tenantId)) {
			tenantId = "000000";
		}
		R<UserInfo> userInfoR = userClient.userInfo(tenantId, account);
		if (userInfoR == null || userInfoR.getData() == null || userInfoR.getData().getUser() == null) {
			return R.fail(500, TokenUtil.USER_NOT_EXIST);
		}
		User user = userInfoR.getData().getUser();
		String userEmail = user.getEmail();
		if (StringUtils.isEmpty(userEmail) || !email.equals(userEmail)) {
			return R.fail(500, TokenUtil.USER_NOT_EMAIL);
		}
		boolean matches = Pattern.matches(emailMatcher, userEmail);
		if (!matches) {
			return R.fail(500, TokenUtil.USER_NOT_EMAIL);
		}
		String password = PasswordUtils.randomPW();
		User updateUser = new User();
		Date date = new Date();
		updateUser.setId(user.getId());
		updateUser.setUpdateTime(date);
		updateUser.setPasswordUpdate(date);
		updateUser.setPassword(password);
		R<Boolean> booleanR = userClient.updateUser(updateUser);
		if(!booleanR.getData()){
			return R.fail("操作失败,请重试");
		}
		List<String> userEmails = new ArrayList<>();
		userEmails.add(userEmail);
		emailCommonUtil.sendMail(userEmails, StaticConstant.USER_PASSWORD_EMAIL_THEME, StaticConstant.USER_PASSWORD_EMAIL_TITLE, StaticConstant.USER_PASSWORD_EMAIL_CONTENT + password);
		return R.success("操作成功,密码已发送到邮箱请查收");
	}
	@GetMapping("/captchas")
	@ApiOperation(value = "获取验证码")
	public R<Kv> captcha() {
		SpecCaptcha specCaptcha = new SpecCaptcha(130, 48, 5);
		String verCode = specCaptcha.text().toLowerCase();
		String key = UUID.randomUUID().toString();
		// 存入redis并设置过期时间为30分钟
		redisUtil.set(CacheNames.CAPTCHA_KEY + key, verCode, 30L, TimeUnit.MINUTES);
		// 将key和base64返回给前端
		return R.data(Kv.init().set("key", key).set("image", specCaptcha.toBase64()));
	}
	/**
	 * 验证码生成
	 */
	@GetMapping(value = "/captcha")
	@ApiOperation(value = "获取验证码")
	public R<Kv> getKaptchaImage(@ApiParam(value = "验证码类型") @RequestParam(defaultValue = "math", required = false) String type) throws IOException {
		type = type == null ? "math" : type;
		String capStr = "";
		String code = null;
		BufferedImage bi = null;
		if ("math".equals(type)) {
			String capText = captchaProducerMath.createText();
			capStr = capText.substring(0, capText.lastIndexOf("@"));
			code = capText.substring(capText.lastIndexOf("@") + 1);
			bi = captchaProducerMath.createImage(capStr);
		} else if ("char".equals(type)) {
			capStr = code = captchaProducer.createText();
			//bi = captchaProducer.createImage(capStr);
		}
		// 存入redis并设置过期时间为30分钟
		String key = UUID.randomUUID().toString();
		redisUtil.set(CacheNames.CAPTCHA_KEY + key, code, 30L, TimeUnit.MINUTES);
		ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
		ImageIO.write(bi, "jpg", outputStream);
//		byte b[] = capStr.getBytes();
//		outputStream.write(b);
		return R.data(Kv.init().set("key", key).set("image", "data:image/png;base64,"+Base64.getEncoder().encodeToString(outputStream.toByteArray())));


	}
}

